﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.Creation;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YJKArchKernel.OutWallSearch;
using YJKArchMethodLibrary.Utils;
using YJKDrawSelectArea;
using YJKFloor.EnumDefine;
using YJKFloor.Forms;
using TopologySearch;

namespace YJKFloor.CreateFloor
{
	public class UserOperationManager
	{
		public UserOperationManager(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
			this.m_ActiveView = this.m_Revit.Application.ActiveUIDocument.ActiveView;
		}

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result SelectGenerationMethod(ref string message)
		{
			List<FloorType> floorTypeList = new List<FloorType>();
			List<string> levelNameList = new List<string>();
			string name = this.m_ActiveView.GenLevel.Name;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			if (this.GetInitializeData(ref floorTypeList, ref levelNameList, ref message) != null)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			List<WallData> lstInputOutWall = new List<WallData>();
			OutWallFilter.Search(this.m_Doc, (this.m_ActiveView as ViewPlan).Id, ref lstInputOutWall, true, true);
			SearchFloorForm searchFloorForm = new SearchFloorForm(this.m_Revit, floorTypeList, levelNameList, name);
			searchFloorForm.Show(CreateFloorCmd._hWndRevit);
			searchFloorForm.Refresh();
			OffsetCurveManager offsetCurveManager = new OffsetCurveManager(this.m_Revit, searchFloorForm);
            Assist.RoomFilter roomFilter = new Assist.RoomFilter();
			List<Element> list = new List<Element>();
			while (!searchFloorForm.IsDisposed)
			{
				if (SelectType.ST_FreeDraw == searchFloorForm.SelType)
				{
					if (Result.Failed == this.FreeDrawMethod(searchFloorForm, selection))
					{
					}
				}
				else
				{
					try
					{
						int wMsg = 7;
						UserOperationManager.SendMessage(CreateFloorCmd._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
						list.Clear();
						if (SelectType.ST_SelectRoom == searchFloorForm.SelType)
						{
							IList<Element> source = selection.PickElementsByRectangle(roomFilter, "请框选房间生成楼板");
							list = source.ToList<Element>();
						}
						else
						{
							IList<Reference> list2 = selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, roomFilter, "请多选房间生成楼板");
							foreach (Reference reference in list2)
							{
								list.Add(this.m_Doc.GetElement(reference));
							}
						}
						if (list.Count == 0)
						{
							continue;
						}
					}
					catch (Autodesk.Revit.Exceptions.OperationCanceledException)
					{
						if (searchFloorForm.IsClickMode)
						{
							searchFloorForm.IsClickMode = false;
							continue;
						}
						searchFloorForm.Close();
						return Autodesk.Revit.UI.Result.Succeeded;
					}
					try
					{
						List<Room> lstInputRooms = list.Cast<Room>().ToList<Room>();
						if (!offsetCurveManager.CreateFloor(lstInputOutWall, this.m_lstLevels, lstInputRooms))
						{
							YJKMessageBox.Show("无法生成楼板，请确认搜索范围是否合理，或者修改搜索的边界条件。");
						}
						else
						{
							YJKMessageBox.Show("楼板生成成功!");
						}
					}
					catch (Exception)
					{
						searchFloorForm.Close();
						return Autodesk.Revit.UI.Result.Succeeded;
					}
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result FreeDrawMethod(SearchFloorForm dlg, Selection tempSelect)
		{
			if (SelectAreaManager._hWndRevit == null)
			{
				SelectAreaManager._hWndRevit = CreateFloorCmd._hWndRevit;
			}
			SelectAreaManager selectAreaManager = new SelectAreaManager(this.m_Revit, false);
			if (selectAreaManager.EditOutLine() != null)
			{
				YJKMessageBox.Show("选择区域失败");
				dlg.Close();
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			if (!selectAreaManager.IfWinFormClose)
			{
			}
			if (selectAreaManager.m_lstDetailCurveId.Count <= 0)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			if (this.CreateFloorByFreeDraw(dlg, selectAreaManager.m_lstDetailCurveId))
			{
				YJKMessageBox.Show("楼板生成成功!");
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			YJKMessageBox.Show("绘制区域未闭合，无法生成楼板!");
			return Autodesk.Revit.UI.Result.Failed;
		}

		private bool CreateFloorByFreeDraw(SearchFloorForm m_CreateFloorForm, List<ElementId> lstInputDrawCv)
		{
			new CurveArray();
			List<Pole2D> list = new List<Pole2D>();
			List<List<Curve>> list2 = new List<List<Curve>>();
			List<List<ElementId>> list3 = new List<List<ElementId>>();
            Autodesk.Revit.Creation.Document create = this.m_Doc.Create;
			double num = Common.MMToFeet(m_CreateFloorForm.ElevationOffset);
			double value = Common.MMToFeet(m_CreateFloorForm.BoundaryOffset);
			foreach (ElementId elementId in lstInputDrawCv)
			{
				if (this.m_Doc.GetElement(elementId) is DetailCurve)
				{
					Curve geometryCurve = (this.m_Doc.GetElement(elementId) as DetailCurve).GeometryCurve;
					Pole2D item = Pole2D.TransformWallToStructure2DPole(geometryCurve, ElementId.InvalidElementId, Math.Abs(value), Math.Abs(value));
					list.Add(item);
				}
			}
			double dEps = 0.01;
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(this.m_Revit, dEps);
			list2 = structureLoopSearcher.GetFullFloorEdgeLoops(list, false, ref list3, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
			int num2 = 0;
			Transaction transaction = new Transaction(this.m_Doc, "Create Floors");
			transaction.Start();
			bool result;
			try
			{
				foreach (List<Curve> list4 in list2)
				{
					CurveArray curveArray = new CurveArray();
					foreach (Curve curve in list4)
					{
						curveArray.Append(curve);
					}
					try
					{
						Floor floor = create.NewFloor(curveArray, m_CreateFloorForm.SelFloorType, this.m_lstLevels[m_CreateFloorForm.LevelIndex], false);
						if (floor != null)
						{
							floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(num);
							num2++;
						}
					}
					catch (Exception)
					{
					}
				}
				this.DeleteSelectLine(lstInputDrawCv);
				transaction.Commit();
				if (num2 > 0)
				{
					result = true;
				}
				else
				{
					result = false;
				}
			}
			catch (Exception)
			{
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				result = false;
			}
			return result;
		}

		private void DeleteSelectLine(List<ElementId> lstSelLineId)
		{
			try
			{
				this.m_Doc.Delete(lstSelLineId);
			}
			catch
			{
			}
		}

		private Result GetInitializeData(ref List<FloorType> lstFloorTypes, ref List<string> lstLevelName, ref string message)
		{
			List<FloorType> list = new List<FloorType>();
			list = this.GetFloorType();
			if (list.Count == 0)
			{
				message = "楼板类型列表为空";
				return Autodesk.Revit.UI.Result.Failed;
			}
			foreach (FloorType item in list)
			{
				lstFloorTypes.Add(item);
			}
			this.m_lstLevels = Common.GetSortLevels(this.m_Doc, double.MinValue, double.MaxValue);
			if (this.m_lstLevels.Count == 0)
			{
				message = "标高列表为空";
				return Autodesk.Revit.UI.Result.Failed;
			}
			foreach (Level level in this.m_lstLevels)
			{
				lstLevelName.Add(level.Name);
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private List<FloorType> GetFloorType()
		{
			List<FloorType> list = new List<FloorType>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Doc);
			ICollection<Element> collection = filteredElementCollector.OfClass(typeof(FloorType)).ToElements();
			foreach (Element element in collection)
			{
				FloorType floorType = element as FloorType;
				if (floorType.Category.Id.IntegerValue == -2000032)
				{
					list.Add(floorType);
				}
			}
			return list;
		}

		private ExternalCommandData m_Revit;

        private Autodesk.Revit.DB.Document m_Doc;

		private View m_ActiveView;

		private List<Level> m_lstLevels = new List<Level>();
	}
}
